<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>1.1 Object数据动态检测复习</title>
</head>
<body>
    <div>
        <h2>
            1.1 Object数据动态检测复习
        </h2>
        <!-- <button onclick="onclickMethod()">触发一下</button> -->
    </div>
</body>
</html>

<script>

    class Dep {
        constructor(){
            this.subs = []
        }

        addSub(sub){
            this.subs.push(sub)
        }

        depend() {
            if(window.target){
                this.addSub(window.target)
            }            
        }
    
        notify() {
            let subs = this.subs.slice()
            for(let i=0;i<subs.length; i++){
                subs[i].update()
            }
        }
    }


    const bailRE = /[^\w.$]/ // 匹配数字、字母、下划线
    function parsePath(path) {
        if(bailRE.test(path)) return
        const segments = path.split('.')
        return function(obj) {
            for(let i=0;i<segments.length;i++){
                if(!obj) return
                obj = obj[segments[i]]
            }
            return obj
        }
    }

    class Watcher {
        constructor(vm, expOrFn, cb) {
            this.vm = vm
            this.getter = parsePath(expOrFn)
            this.cb = cb
            this.value = this.get()
        }
        get() {
            window.target = this
            let value = this.getter(this.vm, this.vm)
            window.target = undefined
            return value
        }
        update(){
            const oldValue = this.value
            this.value = this.get()
            if(this.value === oldValue) return
            this.cb.call(this.vm, this.value, oldValue)
        }
    }

    function defineReactive(data, key, val){
        if(typeof val === 'object') new Observer(val)
        let dep = new Dep()
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get() {
                dep.depend()
                return val
            },
            set(newVal) {
                if(newVal === val) {
                    // console.log('set中的new:', newVal);
                    // console.log('set中的old:', val);
                    return
                }
                console.log('来了一次');
                val = newVal
                dep.notify()
            }
        })
    }

    class Observer {
        constructor(value) {
            this.value = value
            if(Array.isArray(this.value)){
                
            } else {
                this.walk(this.value)
            }
        }

        walk(obj) {
            console.log('obj:', obj);
            const keys = Object.keys(obj)
            console.log('keys', keys);
            for(let i=0;i<keys.length;i++){
                defineReactive(obj, keys[i], obj[keys[i]]) 
            }
        }
        
        
    }
    
    this.data = {
        userInfo: {
            name: '111',
            job: ''
        }
    }

    new Observer(this.data)
    new Watcher(this, 'data.userInfo.name', (newVal, oldVal) => {
        console.log('新值:', newVal);
        console.log('旧值:', oldVal);
    })
    
    this.data.userInfo.name = '蒋皓天'
    this.data.userInfo.name = '周钰'
    this.data.userInfo.name = '谷川'
</script>